---
title: TypeScript
description: Integrate Latitude into your Node.js applications using the TypeScript SDK.
---

The Latitude TypeScript SDK provides a convenient way to interact with the Latitude platform from your Node.js or browser applications.

## Installation

The Latitude SDK is compatible with Node.js 16 or higher.

```bash
npm install @latitude-data/sdk
# or
yarn add @latitude-data/sdk
# or
pnpm add @latitude-data/sdk
```

## Authentication and Initialization

Import the SDK and initialize it with your API key. You can generate API keys in your Latitude project settings under "API Access".

```typescript
import { Latitude } from '@latitude-data/sdk'

const latitude = new Latitude(process.env.LATITUDE_API_KEY)
```

You can also provide additional options during initialization:

```typescript
const latitude = new Latitude(process.env.LATITUDE_API_KEY, {
  projectId: 123, // Your Latitude project ID
  versionUuid: 'version-uuid', // Optional version UUID
}) // Keep your API key secure and avoid committing it directly into your codebase.
```

> Both `projectId` and `versionUuid` options can be overridden on a per-method basis when needed.

## Examples

Check out our [Examples](/examples) section for more examples of how to use the Latitude SDK.

## SDK Structure

The Latitude SDK is organized into several namespaces:

- `prompts`: Methods for managing and running prompts
- `runs`: Methods for managing active runs
- `logs`: Methods for pushing logs to Latitude
- `evaluations`: Methods for pushing evaluation results to Latitude
- `projects`: Methods for managing projects
- `versions`: Methods for managing project versions

## Prompt Management

### Get a Prompt

To retrieve a specific prompt by its path:

```typescript
const prompt = await latitude.prompts.get('prompt-path')
```

### Get All Prompts

To retrieve all prompts in your project:

```typescript
const prompts = await latitude.prompts.getAll()
```

### Get or Create a Prompt

To get an existing prompt or create a new one if it doesn't exist:

```typescript
const prompt = await latitude.prompts.getOrCreate('prompt-path')
```

You can also provide the content when creating a new prompt:

```typescript
const prompt = await latitude.prompts.getOrCreate('prompt-path', {
  prompt: 'This is the content of my new prompt',
})
```

## Version Management

### Get All Versions

To retrieve all versions from a project:

```typescript
const versions = await latitude.versions.getAll()
```

You can also specify a different project ID:

```typescript
const versions = await latitude.versions.getAll(123)
```

## Running Prompts

### Non-Streaming Run

Execute a prompt and get the complete response once generation is finished:

```typescript
const result = await latitude.prompts.run('prompt-path', {
  parameters: {
    productName: 'CloudSync Pro',
    audience: 'Small Business Owners',
  },
  // Disable streaming (enabled by default)
  stream: false,
  // Optional: Provide a custom identifier for this run
  customIdentifier: 'email-campaign-2023',
})

console.log('Conversation UUID:', result.uuid)
console.log('Response:', result.response.text)
```

### Handling Streaming Responses

For real-time applications (like chatbots), use streaming to get response chunks as they are generated:

```typescript
await latitude.prompts.run('prompt-path', {
  parameters: {
    productName: 'CloudSync Pro',
    audience: 'Small Business Owners',
  },
  // Enable streaming
  stream: true,
  // Provide callbacks for events
  onFinished: (result) => {
    // Execution succeeded
    console.log("Stream completed:", result.response.text);
  },
  onError: (error) => {
    // Execution failed
    console.log("Error:", error);
  },
  onEvent: ({ event, data }) => {
    // All events can be individually handled here
    if (event === StreamEventTypes.Provider && data.type === 'text-delta') {
      console.log(data.textDelta)
    } else if (
      event === StreamEventTypes.Latitude &&
      data.type === 'chain-completed'
    ) {
      console.log('Conversation UUID:', data.uuid)
      console.log('Conversation messages:', data.messages)
    }
  },
})
```

### Using Tools with Prompts

You can provide tool handlers that the model can call during execution:

```typescript
await latitude.prompts.run('prompt-path', {
  parameters: {
    query: 'What is the weather in San Francisco?',
  },
  // Define the tools the model can use
  tools: {
    getWeather: async (args, details) => {
      // `args` contains the arguments passed by the model
      // `details` contains context like tool id, name, messages...
      // The result can be anything JSON serializable
      console.log('Getting weather for:', args.location)
      return { temperature: '72°F', conditions: 'Sunny' }
    },
  },
})
```

### Prompts that return structured outputs

By default the sdk assumes your prompt return text. If you expect your prompt
to return structured output you can type it in the `prompts.run` method:

```typescript
const result = await latitude.prompts.run<{ expected: 'property' }>(
  'structured-output-prompt',
)

console.log(result.object) // outputs { expected: 'property' }
```

### Chat with a Prompt

Follow the conversation of a runned prompt:

```typescript
const messages = [
  {
    role: 'user',
    content: 'Hello, how can you help me today?',
  },
]

const result = await latitude.prompts.chat('conversation-uuid', messages, {
  // Chat options are similar to the run method
  onFinished: (result) => {
    console.log('Chat completed:', result.uuid)
  },
  onError: (error) => {
    console.error('Chat error:', error.message)
  },
})

console.log('Conversation UUID:', result.uuid)
console.log('Conversation messages:', result.conversation)
```

<Note>
  Messages follow the [PromptL](/promptl/syntax/messages) format. If you're
  using a different method to run your prompts, you'll need to format your
  messages accordingly.
</Note>

### Running a Prompt in the Background

For long-running prompts, such as large Agent systems, that you don't need to wait for, use background runs:

```typescript
const job = await latitude.prompts.run('prompt-path', {
  parameters: {
    productName: 'CloudSync Pro',
    audience: 'Small Business Owners',
  },
  // Enable background processing
  background: true,
})

console.log('Job UUID:', job.uuid)
// The request returns immediately with a conversation UUID
// You can use this UUID to attach to the run later to check its status or stop it programmatically

const result = await latitude.runs.attach(job.uuid, {
  stream: true,
  onEvent: ({ event, data }) => {
    console.log('Received event:', event, data)
  },
})

console.log('Conversation UUID:', result.uuid)
console.log('Conversation messages:', result.conversation)
```

## Run Management

### Stop a Run

Stop an active conversation that is currently running:

```typescript
await latitude.runs.stop('conversation-uuid')
console.log('Run stopped successfully')
```

### Attach to a Run

Attach to an active conversation to receive its ongoing output:

```typescript
const result = await latitude.runs.attach('conversation-uuid', {
  // Optional: Enable streaming for real-time updates
  stream: true,
  // Optional: Provide callbacks for events
  onEvent: ({ event, data }) => {
    if (event === StreamEventTypes.Provider && data.type === 'text-delta') {
      console.log(data.textDelta)
    }
  },
  onFinished: (result) => {
    console.log('Attach completed:', result.uuid)
  },
  onError: (error) => {
    console.error('Attach error:', error.message)
  },
})

console.log('Conversation UUID:', result.uuid)
console.log('Conversation messages:', result.conversation)
```

## Rendering Prompts

### Prompt Rendering

Render a prompt locally without running it:

```typescript
const result = await latitude.prompts.render({
  prompt: {
    content: 'Your prompt content here with {{ parameters }}',
  },
  parameters: {
    topic: 'Artificial Intelligence',
    tone: 'Professional',
  },
  // Optional: Specify a provider adapter
  adapter: Adapters.OpenAI,
})

console.log('Rendered config:', result.config)
console.log('Rendered messages:', result.messages)
```

### Chain Rendering

Render a chain of prompts locally:

```typescript
const result = await latitude.prompts.renderChain({
  prompt: {
    path: 'prompt-path',
    content: 'Your prompt content here with {{ parameters }}',
    provider: 'openai',
  },
  parameters: {
    topic: 'Machine Learning',
    complexity: 'Advanced',
  },
  // Required: Process each step in the chain
  onStep: async ({ config, messages }) => {
    // Process each step in the chain
    console.log('Processing step with messages:', messages)
    // Return a string or a message object
    return 'Step response'
  },
  // Optional: Specify a provider adapter
  adapter: Adapters.OpenAI,
  // Optional: Log responses to Latitude
  logResponses: true,
  // Optional: Define tools for the chain
  tools: {
    getExample: async (args, details) => {
      return { example: 'This is an example response' }
    },
  },
})

console.log('Rendered config:', result.config)
console.log('Rendered messages:', result.messages)
```

### Agent Rendering

Render an agent prompt locally (similar to `renderChain` but with a final agent result):

```typescript
const result = await latitude.prompts.renderAgent({
  prompt: {
    path: 'prompt-path',
    content: 'Agent prompt content with {{ parameters }}',
    provider: 'openai',
  },
  parameters: {
    task: 'Research quantum computing',
    depth: 'Detailed',
  },
  // Required: Process each agent step
  onStep: async ({ config, messages }) => {
    // Process each step in the agent execution
    console.log('Processing agent step:', messages)
    // Return a string or a message object
    return 'Agent step response'
  },
  // Optional: Log responses to Latitude
  logResponses: true,
  // Optional: Define tools for the agent
  tools: {
    search: async (args, details) => {
      console.log('Agent using search tool with args:', args)
      return { results: ['Result 1', 'Result 2'] }
    },
  },
})

console.log('Rendered config:', result.config)
console.log('Rendered messages:', result.messages)
// Agent final response is available in result.result
console.log('Agent final response:', result.result)
```

<Note>
  Make sure to provide the `config.tools` parameter to the LLM provider in your
  `onStep` handler, otherwise the AI won't be able to stop the Agent loop!
</Note>

## Logging

### Creating Logs

Push a log to Latitude manually for a prompt:

```typescript
const messages = [
  {
    role: 'user',
    content: 'Hello, how can you help me today?',
  },
]

const log = await latitude.logs.create('prompt-path', messages, {
  response: 'I can help you with anything!',
})
```

## Evaluations

### Annotate a log

Push an evaluation result (annotate) to Latitude:

```typescript
const result = await latitude.evaluations.annotate(
  'conversation-uuid',
  100,
  'evaluation-uuid',
  {
    reason: 'I liked it!',
  },
)
```

## Complete Method Reference

### Initialization

```typescript
// SDK initialization
new Latitude(
  apiKey: string,
  options: {
    projectId?: number,
    versionUuid?: string,
    __internal?: {
      gateway?: GatewayApiConfig,
      source?: LogSources,
      retryMs?: number
    }
  }
)
```

### Prompts Namespace

```typescript
// Get a prompt
latitude.prompts.get(
  path: string,
  options?: {
    projectId?: number,
    versionUuid?: string
  }
): Promise<Prompt>

// Get all prompts
latitude.prompts.getAll(
  options?: {
    projectId?: number,
    versionUuid?: string
  }
): Promise<Prompt[]>

// Create a prompt
latitude.prompts.create(
  path: string,
  options?: {
    projectId?: number,
    versionUuid?: string,
    prompt?: string
  }
): Promise<Prompt>

// Get or create a prompt
latitude.prompts.getOrCreate(
  path: string,
  options?: {
    projectId?: number,
    versionUuid?: string,
    prompt?: string
  }
): Promise<Prompt>

// Run a prompt
latitude.prompts.run<S extends AssertedStreamType = 'text', Tools extends ToolSpec = {}, Background extends boolean = false>(
  path: string,
  options: {
    projectId?: number,
    versionUuid?: string,
    customIdentifier?: string,
    parameters?: Record<string, unknown>,
    stream?: boolean,
    background?: Background,
    tools?: ToolCalledFn<Tools>,
    signal?: AbortSignal,
    onEvent?: ({ event, data }: { event: StreamEventTypes, data: ChainEventDto }) => void,
    onFinished?: (data: GenerationResponse<S>) => void,
    onError?: (error: LatitudeApiError) => void
  }
): Promise<RunPromptResult<S, Background> | undefined>

// Chat with a prompt
latitude.prompts.chat<S extends AssertedStreamType = 'text', Tools extends ToolSpec = {}>(
  uuid: string,
  messages: Message[],
  options?: {
    stream?: boolean,
    tools?: ToolCalledFn<Tools>,
    signal?: AbortSignal,
    onEvent?: ({ event, data }: { event: StreamEventTypes, data: ChainEventDto }) => void,
    onFinished?: (data: GenerationResponse<S>) => void,
    onError?: (error: LatitudeApiError) => void
  }
): Promise<GenerationResponse<S> | undefined>

// Render a prompt
latitude.prompts.render<M extends AdapterMessageType = PromptlMessage>(
  options: {
    prompt: { content: string },
    parameters: Record<string, unknown>,
    adapter?: ProviderAdapter<M>
  }
): Promise<{ config: Config, messages: M[] }>

// Render a chain
latitude.prompts.renderChain<M extends AdapterMessageType = PromptlMessage>(
  options: {
    prompt: Prompt,
    parameters: Record<string, unknown>,
    adapter?: ProviderAdapter<M>,
    onStep: (args: { config: Config, messages: M[] }) => Promise<string | Omit<M, 'role'>>,
    tools?: RenderToolCalledFn<ToolSpec>,
    logResponses?: boolean
  }
): Promise<{ config: Config, messages: M[] }>
```

### Runs Namespace

```typescript
// Attach to a run
latitude.runs.attach<S extends AssertedStreamType = 'text', Tools extends ToolSpec = {}>(
  uuid: string,
  options?: {
    stream?: boolean,
    tools?: ToolCalledFn<Tools>,
    signal?: AbortSignal,
    onEvent?: ({ event, data }: { event: StreamEventTypes, data: ChainEventDto }) => void,
    onFinished?: (data: GenerationResponse<S>) => void,
    onError?: (error: LatitudeApiError) => void
  }
): Promise<GenerationResponse<S> | undefined>

// Stop a run
latitude.runs.stop(uuid: string): Promise<void>
```

### Projects Namespace

```typescript
// Get all projects
latitude.projects.getAll(): Promise<Project[]>

// Create a project
latitude.projects.create(
  name: string
): Promise<{
  project: Project
  version: Version
}>
```

### Logs Namespace

```typescript
// Create a log
latitude.logs.create(
  path: string,
  messages: Message[],
  options?: {
    response?: string,
    projectId?: number,
    versionUuid?: string
  }
): Promise<DocumentLog>
```

### Evaluations Namespace

```typescript
// Annotate a log
latitude.evaluations.annotate(
  uuid: string,
  score: number,
  evaluationUuid: string,
  options?: {
    reason?: string,
    versionUuid?: string
  }
): Promise<PublicManualEvaluationResultV2>
```

### Versions Namespace

```typescript
// Get a version
latitude.versions.get(
  projectId: number,
  commitUuid: string
): Promise<Version>

// Get all versions
latitude.versions.getAll(projectId?: number): Promise<Version[]>

// Create a version
latitude.versions.create(
  name: string,
  options?: {
    projectId?: number
  }
): Promise<Version>

// Push version changes
latitude.versions.push(
  projectId: number,
  baseCommitUuid: string,
  changes: Array<{
    path: string
    content: string
    status: 'added' | 'modified' | 'deleted' | 'unchanged'
    contentHash?: string
  }>
): Promise<{ commitUuid: string }>
```

## Error Handling

The SDK throws `LatitudeApiError` instances when API requests fail. You can catch and handle these errors:

```typescript
import { LatitudeApiError } from '@latitude-data/sdk'

async function handleErrors() {
  try {
    const prompt = await latitude.prompts.get('non-existent-prompt')
  } catch (error) {
    if (error instanceof LatitudeApiError) {
      console.error('API Error:', error.message)
      console.error('Error Code:', error.errorCode)
      console.error('Status:', error.status)
    } else {
      console.error('Unexpected error:', error)
    }
  }
}
```

## Logging Features

- **Automatic Logging**: All runs through `latitude.prompts.run()` are automatically logged in Latitude, capturing inputs, outputs, performance metrics, and trace information.
- **Custom Identifiers**: Use the optional `customIdentifier` parameter to tag runs for easier filtering and analysis in the Latitude dashboard.
- **Response Identification**: Each response includes identifying information like `uuid` that can be used to reference the specific run later.

## Further Information

- [HTTP API Reference](/guides/api/reference)
- [API Access and Authentication](/guides/api/api-access)
- [Streaming Event Details](/guides/api/streaming-events)
